"""Support for LaMetric switches."""

from __future__ import annotations

from collections.abc import Awaitable, Callable
from dataclasses import dataclass
from typing import Any

from demetriek import Device, LaMetricDevice

from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .coordinator import LaMetricConfigEntry, LaMetricDataUpdateCoordinator
from .entity import LaMetricEntity
from .helpers import lametric_exception_handler


@dataclass(frozen=True, kw_only=True)
class LaMetricSwitchEntityDescription(SwitchEntityDescription):
    """Class describing LaMetric switch entities."""

    available_fn: Callable[[Device], bool] = lambda device: True
    has_fn: Callable[[Device], bool] = lambda device: True
    is_on_fn: Callable[[Device], bool]
    set_fn: Callable[[LaMetricDevice, bool], Awaitable[Any]]


SWITCHES = [
    LaMetricSwitchEntityDescription(
        key="bluetooth",
        translation_key="bluetooth",
        entity_category=EntityCategory.CONFIG,
        available_fn=lambda device: bool(
            device.bluetooth and device.bluetooth.available
        ),
        has_fn=lambda device: bool(device.bluetooth),
        is_on_fn=lambda device: bool(device.bluetooth and device.bluetooth.active),
        set_fn=lambda api, active: api.bluetooth(active=active),
    ),
]


async def async_setup_entry(
    hass: HomeAssistant,
    entry: LaMetricConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up LaMetric switch based on a config entry."""
    coordinator = entry.runtime_data
    async_add_entities(
        LaMetricSwitchEntity(
            coordinator=coordinator,
            description=description,
        )
        for description in SWITCHES
        if description.has_fn(coordinator.data)
    )


class LaMetricSwitchEntity(LaMetricEntity, SwitchEntity):
    """Representation of a LaMetric switch."""

    entity_description: LaMetricSwitchEntityDescription

    def __init__(
        self,
        coordinator: LaMetricDataUpdateCoordinator,
        description: LaMetricSwitchEntityDescription,
    ) -> None:
        """Initiate LaMetric Switch."""
        super().__init__(coordinator)
        self.entity_description = description
        self._attr_unique_id = f"{coordinator.data.serial_number}-{description.key}"

    @property
    def available(self) -> bool:
        """Return if entity is available."""
        return super().available and self.entity_description.available_fn(
            self.coordinator.data
        )

    @property
    def is_on(self) -> bool:
        """Return state of the switch."""
        return self.entity_description.is_on_fn(self.coordinator.data)

    @lametric_exception_handler
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the entity on."""
        await self.entity_description.set_fn(self.coordinator.lametric, True)
        await self.coordinator.async_request_refresh()

    @lametric_exception_handler
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the entity off."""
        await self.entity_description.set_fn(self.coordinator.lametric, False)
        await self.coordinator.async_request_refresh()
